//
//  LTHmEcgDrawLineView.m
//  TH_HM_CombineSDKTestDemo
//
//  Created by lanzhongping on 2020/11/21.
//  Copyright © 2020 None. All rights reserved.
//

#import "LTRingEcgDrawLineView.h"
#import "ConfigModel.h"

#define ECGLINE_COLOR_DEFAULT  ( [UIColor greenColor])

NSUInteger const VALUE_UPDATE_SPEED = 512; //ecg value come in count per second
NSInteger const NEED_FRESH = 8; // every add  NEED_FRESH point to fresh line

char * const queueNm = "LTHmEcgDrawLineView_Queue";

@interface LTRingEcgDrawLineView()
@property(strong, nonatomic) NSNumber *xSpeed; //走纸速度(x speed)
@property(strong, nonatomic) NSNumber *yGain;  //y增益(y gain)
@end

@implementation LTRingEcgDrawLineView
{
    NSMutableArray<LTHmEcgDrawLineModel *> *_valueArray;// store ecg value
    
    const NSArray<NSNumber *> * _xSpeedArray;
    const NSArray<NSNumber *> * _yGainArray;
        
    NSNumber *_xOffset; // 水平间隔(Horizontal interval)
    CGFloat _transEcgValueToYPT; // 垂直间隔(Vertical separation)
    
    UIBezierPath *_linePath;            // ecg line path
    __weak CAShapeLayer *_ecgLineLayer; // draw ecg line
    NSUInteger _maxPointPerScreen;      //一屏幕最多的点数(Most points on a screen)
    
    dispatch_queue_t _serialQueue;
    
    CGFloat _startY;
    
    NSInteger _controlDrawLineTime;
    CGFloat _maxWidth; // max width to show
}

-(instancetype)init
{
    if (self = [super init]) {
        // 25 mm/s ,50 mm/s
        _xSpeedArray = @[@(25.0f), @(50.0f)];           // cannot modify
        //5 mm/mv,  10 mm/mv ,20 mm/mv
        _yGainArray = @[@(5.0f), @(10.0f), @(20.0f)];   // cannot modify
        
        _valueArray = [[NSMutableArray alloc]init];
        self.xSpeed = _xSpeedArray[HORIZONTAL_SPEED_DEFAULT]; //
        self.yGain = _yGainArray[VERTIAL_GAIN_DEFAULT];
        _linePath = [UIBezierPath bezierPath];
        _serialQueue = dispatch_queue_create(queueNm, DISPATCH_QUEUE_SERIAL);
        self.userInteractionEnabled = NO;
    }
    
    return self;
}


-(void)setHorizonalSpeed:(HORIZONTAL_SPEED)speedType VertialGain:(VERTIAL_GAIN)vGain
{
    if (speedType >= _xSpeedArray.count) {
        speedType = HORIZONTAL_SPEED_DEFAULT;
    }
    
    if (vGain >= _yGainArray.count) {
        vGain = VERTIAL_GAIN_DEFAULT;
    }
    self.xSpeed = _xSpeedArray[speedType];
    self.yGain = _yGainArray[vGain];
    
}

-(void)updateValues:(NSArray<NSNumber *> *)ecgValueArray
{
    WEAK_SELF
    dispatch_async(_serialQueue, ^{
        STRONG_SELF
        for (NSNumber *obj in ecgValueArray) {
            CGFloat ecgValue = obj.floatValue;
            LTHmEcgDrawLineModel *newModel = [[LTHmEcgDrawLineModel alloc]initWithWave:ecgValue];
            //预先计算Y坐标(Pre calculation of Y coordinates)
            CGFloat pointY = strongSelf->_startY + newModel.ecgWaveValue * strongSelf->_transEcgValueToYPT;
            if (pointY > strongSelf->_startY * 2) {
                pointY = strongSelf->_startY * 2;
            } else if (pointY < 0.0f) {
                pointY = 0.0f;
            }
            newModel.pointY = pointY;
            
            [strongSelf->_valueArray addObject:newModel];
            strongSelf->_controlDrawLineTime++;
            if (strongSelf->_valueArray.count > strongSelf->_maxPointPerScreen) {
                [strongSelf->_valueArray removeObjectAtIndex:0]; //remove first value
            }
        }
    
        /*
         1 延时处理, 每新增8个点渲染一次 每个点间隔约2ms,
         2 iphone刷新率 60帧/s => 一帧16.6秒, 每一帧间隔刷新一次
         
         1 Delay processing, rendering once every 8 new points, and the interval between each point is about 2ms,
         2 The refresh rate of iPhone is 60 frames / S = > 16.6 seconds per frame, and it is refreshed once every frame interval
         */
//        if (strongSelf->_controlDrawLineTime % NEED_FRESH == 0) {
            [strongSelf drawLine];
//            strongSelf->_controlDrawLineTime = 0;
//        }
    });
}


-(void)updateValue:(CGFloat)ecgValue
{
    WEAK_SELF
    dispatch_async(_serialQueue, ^{
        STRONG_SELF
        LTHmEcgDrawLineModel *newModel = [[LTHmEcgDrawLineModel alloc]initWithWave:ecgValue];
        //预先计算Y坐标(Pre calculation of Y coordinates)
        CGFloat pointY = strongSelf->_startY + newModel.ecgWaveValue * strongSelf->_transEcgValueToYPT;
        if (pointY > strongSelf->_startY * 2) {
            pointY = strongSelf->_startY * 2;
        } else if (pointY < 0.0f) {
            pointY = 0.0f;
        }
        newModel.pointY = pointY;
        
        [strongSelf->_valueArray addObject:newModel];
        strongSelf->_controlDrawLineTime++;
        if (strongSelf->_valueArray.count > strongSelf->_maxPointPerScreen) {
            [strongSelf->_valueArray removeObjectAtIndex:0]; //remove first value
        }
        
        /*
         1 延时处理, 每新增8个点渲染一次 每个点间隔约2ms,
         2 iphone刷新率 60帧/s => 一帧16.6秒, 每一帧间隔刷新一次
         
         1 Delay processing, rendering once every 8 new points, and the interval between each point is about 2ms,
         2 The refresh rate of iPhone is 60 frames / S = > 16.6 seconds per frame, and it is refreshed once every frame interval
         */
        if (strongSelf->_controlDrawLineTime % NEED_FRESH == 0) {
            [self drawLine];
            strongSelf->_controlDrawLineTime = 0;
        }
    });
    
}
-(void)reset
{
    [_valueArray removeAllObjects];
    [_linePath removeAllPoints];
    _ecgLineLayer.path = nil;
    _controlDrawLineTime = 0;
}


-(void)layoutSubviews
{
    [super layoutSubviews];
    [self prepareDrawData];
    
}


- (void)drawLine
{
    [_linePath removeAllPoints];
    
    CGPoint startPoint = CGPointMake(0.0f, _startY);
    [_linePath moveToPoint:startPoint];
    // calc every point
    NSArray<LTHmEcgDrawLineModel *> *drawArray = [_valueArray mutableCopy];
    
    
    [drawArray enumerateObjectsUsingBlock:^(LTHmEcgDrawLineModel * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        
        CGFloat pointX = _xOffset.floatValue * idx;
        if (pointX > _maxWidth) {
            return; //out of  view
        }
        CGFloat pointY = obj.pointY;
        CGPoint point = CGPointMake(pointX, pointY);
        [_linePath addLineToPoint:point];
        [_linePath moveToPoint:point];
    }];
    
//    for (int i = 0 ; i < drawArray.count; i++) {
//        CGFloat pointX = _xOffset.floatValue * i;
//        if (pointX > _maxWidth) {
//            continue; //cannot show in  view
//        }
//        CGFloat pointY = drawArray[i].pointY;
//        CGPoint point = CGPointMake(pointX, pointY);
//        [_linePath addLineToPoint:point];
//        [_linePath moveToPoint:point];
//
//    }
    
    CGPathRef cgpath = _linePath.CGPath;
    CGPathRetain(cgpath);
    WEAK_SELF
    dispatch_async(dispatch_get_main_queue(), ^{
        STRONG_SELF
        strongSelf->_ecgLineLayer.path = cgpath;
        CGPathRelease(cgpath);
        
    });
    
    
}


- (void)prepareDrawData
{

    if (_ecgLineLayer) {
        [_ecgLineLayer removeFromSuperlayer];
    }
    
    CAShapeLayer *lineLayer = [CAShapeLayer layer];
    lineLayer.frame = self.bounds;
    [self.layer addSublayer:lineLayer];
    _ecgLineLayer = lineLayer;
    _ecgLineLayer.strokeEnd = kCGLineCapSquare;
    _ecgLineLayer.lineWidth = 1.0f;
    if (!_ecgLineColor) {
        _ecgLineColor = ECGLINE_COLOR_DEFAULT;
    }
    _ecgLineLayer.strokeColor = _ecgLineColor.CGColor;
    
    //确定一屏最多点数(calc max count of point per screen)
    _maxPointPerScreen = (NSUInteger)(self.bounds.size.width / _xOffset.floatValue);
    _startY = self.bounds.size.height / 2.0f;
    _maxWidth = self.bounds.size.width;
}


-(void)setXSpeed:(NSNumber *)xSpeed
{
    _xSpeed = xSpeed;
    //计算水平走纸速度 单位 pt
    CGFloat xspeedPT = _xSpeed.floatValue / VALUE_UPDATE_SPEED * TRANS_MM_TO_PT ;
    _xOffset = @(xspeedPT);
    
}

-(void)setYGain:(NSNumber *)yGain
{
    _yGain = yGain;
    // 固定公式 (Fixed formula) : (18.3f / 128.0f / 100.0f) 
    [self freshTransEcgValueToYPT];
//    CGFloat scaleCustom = 1;//
//    CGFloat screenScale = [UIScreen mainScreen].scale;
//    CGFloat transEcgValueToYPT =  scaleCustom * _yGain.floatValue * TRANS_MM_TO_PT * self.direction ;
//    _transEcgValueToYPT = transEcgValueToYPT;
//    NSLog(@"lzp _transEcgValueToYPT = %f", _transEcgValueToYPT);
}

-(void)setDirection:(NSInteger)direction
{
    _direction = direction;
    [self freshTransEcgValueToYPT];

}

-(void)freshTransEcgValueToYPT {
    CGFloat scaleCustom = 1;//
    CGFloat screenScale = [UIScreen mainScreen].scale;
    CGFloat transEcgValueToYPT =  scaleCustom * _yGain.floatValue * TRANS_MM_TO_PT * self.direction ;
    _transEcgValueToYPT = transEcgValueToYPT;
}


-(CGFloat)calcHistoryWidth:(NSInteger)count
{
    CGFloat width = _xOffset.floatValue * count;
    return width;
}

-(void)drawAllData:(NSArray<NSNumber *> *)allData
{
    self.layer.masksToBounds = YES;
    if (allData.count == 0) {
        _ecgLineLayer.path = nil;
        return;
    }
    WEAK_SELF
    dispatch_async(_serialQueue, ^{
        STRONG_SELF
        [strongSelf->_linePath removeAllPoints];
        CGPoint startPoint = CGPointMake(0.0f, strongSelf->_startY);
        [strongSelf->_linePath moveToPoint:startPoint];
        
        [allData enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            
            CGFloat pointX = strongSelf->_xOffset.floatValue * idx;
            CGFloat pointY = strongSelf->_startY + obj.floatValue * strongSelf->_transEcgValueToYPT;
            if (pointY > strongSelf->_startY * 2) {
                pointY = strongSelf->_startY * 2;
            } else if (pointY < 0.0f) {
                pointY = 0.0f;
            }
            CGPoint point = CGPointMake(pointX, pointY);
            [strongSelf->_linePath addLineToPoint:point];
            [strongSelf->_linePath moveToPoint:point];
        }];
        
        CGPathRef cgpath = strongSelf->_linePath.CGPath;
        CGPathRetain(cgpath);
        dispatch_async(dispatch_get_main_queue(), ^{
            STRONG_SELF
            strongSelf->_ecgLineLayer.path = cgpath;
            CGPathRelease(cgpath);
            
        });
    });
    
}


-(void)dealloc
{
    
    
}

@end


@implementation LTHmEcgDrawLineModel
- (instancetype)initWithWave:(CGFloat)wave {
    if (self = [super init]) {
        self.ecgWaveValue = wave;
    }
    return self;
}
@end
